namespace DA.AnimGraph {
#if UNITY_EDITOR
    [System.Diagnostics.DebuggerTypeProxy(typeof(TimeStateDebugView))]
#endif
    public struct TimeState {
        public enum AccumulateMode : byte {
            Time, // 绝对时间
            Normalize, // 百分比时间
        }

        public AccumulateMode mode { get; private set; }
        public bool isLoop { get; private set; }
        public float duration { get; private set; }

        // mode 为 Normalize 时，baseTime 和 accuTime 都是比例
        public float baseTime { get; private set; }
        public float accuTime { get; private set; }

        public float time => baseTime + accuTime;

        public TimeState(AccumulateMode mode, bool isLoop = false) {
            this.mode = mode;
            baseTime = 0;
            accuTime = 0;
            duration = 0;
            this.isLoop = isLoop;
        }

        /// <summary>
        /// 重置时间，一般是在节点激活时调用
        /// </summary>
        public void Reset(float inBaseTime = 0) {
            baseTime = inBaseTime;
            accuTime = 0;
        }
        /// <summary>
        /// 每次 tick 开始前调用
        /// </summary>
        public void Start() {
            baseTime += accuTime;
            accuTime = 0;
        }

        /// <summary>
        /// 设置总时长，有的设置一次就行，每帧都会变动的要每帧设置一次
        /// 执行 Accumulate() 之前要设置好
        /// </summary>
        public void SetDuration(float duration) {
            this.duration = duration;
        }

        public void Accumulate(float dt) {
            if (mode == AccumulateMode.Time) {
                accuTime += dt;
            } else {
                accuTime += dt / duration;
            }
        }

        public float GetNormalizedTime() {
            if (mode == AccumulateMode.Normalize) {
                return time;
            }
            return time / duration;
        }

        public float GetAbsoluteTime() {
            if (mode == AccumulateMode.Time) {
                return time;
            }
            return time * duration;
        }

        public void GetProgress(out float baseRate, out float accuRate) {
            baseRate = mode == AccumulateMode.Time ? baseTime / duration : baseTime;
            accuRate = mode == AccumulateMode.Time ? accuTime / duration : accuTime;
        }
        public void SetProgress(float baseRate, float accuRate) {
            if (mode == AccumulateMode.Time) {
                baseTime = baseRate * duration;
                accuTime = accuRate * duration;
            } else {
                baseTime = baseRate;
                accuTime = accuRate;
            }
        }
    }

#if UNITY_EDITOR
    internal class TimeStateDebugView {
        private TimeState target;
        public TimeState.AccumulateMode mode => target.mode;
        public bool isLoop => target.isLoop;
        public float duration => target.duration;
        public float baseTime => target.baseTime;
        public float accuTime => target.accuTime;
        public float time => target.time;
        public float normalizedTime => target.GetNormalizedTime();
        public float absoluteTime => target.GetAbsoluteTime();
        public TimeStateDebugView(TimeState target) {
            this.target = target;
        }
    }
#endif
}
